﻿// VirtualCPU.cs
// This program contains a class that simulates an ARM CPU.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;


namespace armsim
{
    /// <summary>
    /// Simulates an ARM CPU. Contains both RAM and Registers
    /// </summary>
    public class VirtualCPU
    {
        /// <summary>
        /// Represents RAM that the CPU can access
        /// </summary>
        public VirtualMemory RAM { get; set; }

        /// <summary>
        /// Represents Registers that the CPU can access
        /// </summary>
        public VirtualRegisters Registers { get; set; }

        /// <summary>
        /// The current instruction to be executed
        /// </summary>
        public BaseInstruction CurrentInstruction { get; set; }

        /// <summary>
        /// The 32 bit encoded instruction to be decoded
        /// </summary>
        public uint LastFetchedInstruction { get; set; }

        /// <summary>
        /// Initializes a new VirtualCPU with Ram and Registers
        /// </summary>
        public VirtualCPU()
        {
            CurrentInstruction = new BaseInstruction(0);
            Registers = new VirtualRegisters();
            RAM = new VirtualMemory();
        }

        /// <summary>
        /// Initializes a new VirtualCPU with a certain number of bytes in ram
        /// </summary>
        /// <param name="ramSize">Number of bytes to be allocated to ram</param>
        public VirtualCPU(uint ramSize)
        {
            CurrentInstruction = new BaseInstruction(0);

            Registers = new VirtualRegisters();
            RAM = new VirtualMemory(ramSize);
        }

        /*
        public VirtualCPU(uint ramSize, uint regSize)
        {
            Registers = new Memory(regSize);
            RAM = new Memory(ramSize);
        }
        */

        /// <summary>
        /// Fetches the next instruction in the virtual CPU using the PC
        /// </summary>
        /// <returns>the fetched instruction</returns>
        public uint Fetch()
        {
            var instruction = RAM.ReadWord(Registers.ReadWord(VirtualMemory.PC));
            if (instruction != 0)
            {
                Registers.WriteWord(VirtualMemory.PC, Registers.ReadWord(VirtualMemory.PC) + 4);
            }

            this.LastFetchedInstruction = instruction;

            return instruction;
        }

        /// <summary>
        /// Executes the instruction
        /// </summary>
        public void Execute()
        {
            // Most of the executing work will be done by the different Instruction classes
            CurrentInstruction.Execute(this);
        }

        /// <summary>
        /// Decodes the LastFectedInstruction into an ArmInstruction
        /// </summary>
        public void Decode()
        {
            // The instruction factory does all the necessary instantiating.
            CurrentInstruction = InstructionFactory.GenerateInstruction(LastFetchedInstruction);
        }

    }
}
